/*============================================================================
  File:      Hierarchies.h
 
  Summary:   Implementation of the DM-dimension hierarchy and the browser 
		     hierarchy for the pair-wise linear regression model.
	
  Date:		 June 30, 2004
------------------------------------------------------------------------------
  This file is part of the Microsoft SQL Server Code Samples.
 
  Copyright (C) 2003 Microsoft Corporation.  All rights reserved.
 
This source code is intended only as a supplement to Microsoft
Development Tools and/or on-line documentation.  See these other
materials for detailed information regarding Microsoft code samples.
 
THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
============================================================================*/
#pragma once
#include <math.h>


// This header implements the two hierarchies for the pair-wise linear regression
// model: the DM-dimension hierarchy and the browser hierarchy. The browser hierarchy
// is constrained to match the regression tree structure so that we can use the
// internal regression tree viewer to see the contents of our model.
//
// Both hierarchies are simply a set of nodes with parent/child relationships. This
// file assigns a unique integer to each node in the hierarchy and implements a 
// corresponding unique naming scheme for the nodes.
//
// For the DM-dimension hierarchy, we need a separate tree for each output variable.
// The integers for the nodes in these trees are assigned as follows: for the 
// ith output attribute in the model, we use:
//
// (1) 3 * i		to represent the root node
// (2) 3 * i + 1	to represent the left child of the root node
// (3) 3 * i + 2	to represent the right child of the root node
//
// For the browser hierarchy, there is a single tree for all of the output attributes.
// The root node of this node has a child for each of the output attributes. This
// child node---from the point of view of the regression tree browser---is the root
// node of an actual decision tree. Because we are simply displaying a regression
// formula, each such root has no children. Our node-assignment scheme is:
//
// (1) #attributes	to represent to root node of the model hierarchy
// (2) i			to represent the root node of the decision tree for the ith
//					output attribute
//
// The unique name for a node is simply the string version of the integer
// as described above.
//
// Thus, for a domain containing 4 output variables, the hierarchies will
// be:
//
// DM Dimension:
// -------------
//
// 0 -> 1
//   -> 2
// 3 -> 4
//	 -> 5
// 6 -> 7
//   -> 8
// 9 -> 10
//   -> 11
//
// Browser
// -------
//
// 5 -> 0
//   -> 1
//	 -> 2
//   -> 3
//   -> 4

// We'll implement the logic of both of these schemes in the following struct.
// Navigation functions will return (ULONG) -1 on failure
	
struct LRPHIERARCHY
{
	LRPHIERARCHY()
	{
		_bDMDimension		= false;
		_ciAttributeOutput	= 0;
	}

	LRPHIERARCHY(bool bDMDimension, UINT ciAttributeOutput)
	{
		_bDMDimension		= bDMDimension;
		_ciAttributeOutput	= ciAttributeOutput;
	}

	// The type of a node: the root node of any output-attribute tree is of type
	// DM_NODE_TYPE_TREE. The root node of the browser hierarchy is of type
	// DM_NODE_TYPE_MODEL. Any non-root leaf node is of type DM_NODE_TYPE_DISTRIBUTION.

	ULONG	UlType(ULONG iID)
	{
		if (_bDMDimension)
		{
			if (BLeaf(iID))
			{
				return DM_NODE_TYPE_TREE_DISTRIBUTION;
			}
			else
			{
				return DM_NODE_TYPE_REGRESSION_TREE_ROOT;
			}
		}
		else
		{
			if (iID == _ciAttributeOutput)
			{
				return DM_NODE_TYPE_MODEL;
			}
			else
			{
				return DM_NODE_TYPE_REGRESSION_TREE_ROOT;
			}
		}
	}

	// Is the ID valid?

	bool	BValidID(ULONG iID)
	{
		if (_bDMDimension)
		{
			return iID < 3 * _ciAttributeOutput;
		}
		else
		{
			return iID <= _ciAttributeOutput;
		}
	}

	ULONG	IiAttribute(ULONG iID)
	{
		if (_bDMDimension)
		{
			return iID / 3;
		}
		else
		{
			if (iID == _ciAttributeOutput)
			{
				return -1;
			}
			else
			{
				return iID;
			}
		}
	}

	ULONG	IIDRootFirst()
	{
		if (_bDMDimension)
		{
			return 0;
		}
		else
		{
			return _ciAttributeOutput;
		}
	}

	ULONG	IIDRootNext(ULONG iIDNode)
	{
		if (_bDMDimension)
		{
			ULONG nCurrAtt	=	IiAttribute(iIDNode); 
			if (nCurrAtt + 1 < _ciAttributeOutput)
			{
				return 3*(nCurrAtt + 1 );
			}
		}
	
		return -1;
	}

	// Does the given ID correspond to a leaf node?
	bool	BLeaf(ULONG iID)
	{
		if (_bDMDimension)
		{
			return ((iID % 3) == 1) || ((iID % 3) == 2);
		}
		else
		{
			return iID != _ciAttributeOutput;
		}
	}
	
	UINT	CChild(ULONG iIDNode)
	{
		if (BLeaf(iIDNode))
		{
			return 0;
		}
		else
		{
			if (_bDMDimension)
			{
				return 2;
			}
			else
			{
				return _ciAttributeOutput;
			}
		}
	}

	ULONG	IIDRoot(UINT iiAttribute)
	{
		if (_bDMDimension)
		{
			return 3 * iiAttribute;
		}
		else
		{
			return iiAttribute;
		}
	}

	// ID of child from ID of parent and child index
	ULONG	IIDChild(ULONG iIDNode, UINT iChild)
	{
		if (iChild >= CChild(iIDNode))
		{
			return -1;
		}

		if (_bDMDimension)
		{
			return IiAttribute(iIDNode) * 3 + iChild + 1;
		}
		else
		{
			return iChild;
		}
	}

	// Child index from child ID
	ULONG	IChild(ULONG iIDChild)
	{
		if (BLeaf(iIDChild) == false)
		{
			return -1;
		}

		if (_bDMDimension)
		{
			return (iIDChild - 1) / 3;
		}
		else
		{
			return iIDChild;
		}
	}

	// Traversing leaves
	ULONG	IIDLeafNext(ULONG iID)
	{
		if (BLeaf(iID) == false)
		{
			// Return the first leaf

			return IIDChild(iID, 0);
		}
		else
		{
			ULONG iChild = IChild(iID);

			return IIDChild(iID, iChild + 1);
		}
	}

	// Parent IDs
	ULONG	IIDParent(ULONG iID)
	{
		if (BLeaf(iID) == false)
		{
			return -1;
		}

		if (_bDMDimension)
		{
			return 3 * IiAttribute(iID);
		}
		else
		{
			return _ciAttributeOutput;
		}
	}

	// Strings
	HRESULT	GetSzFromID(WCHAR* sz, ULONG iID, UINT ccharMax)
	{
		if ((UINT) (log10((double)iID)) >= ccharMax)
		{
			// Caller should provide enough space for the name
			return E_FAIL;
		}

		swprintf_s(sz, ccharMax, L"%d", iID);

		return S_OK;
	}

	ULONG	IDFromSz(const WCHAR* sz)
	{
		return _wtoi(sz);
	}

	bool _bDMDimension;
	UINT _ciAttributeOutput;
};



